package dao

import (
	"context"
	"errors"
	"github.com/go-sql-driver/mysql"
	"go-admin/server/internal/domain"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
	"time"
)

type AdminDao interface {
	Insert(ctx context.Context, admin Admin) error
	Update(ctx context.Context, AdminId int64, admin Admin) error
	UpdateStatus(ctx context.Context, AdminId int64, Status int32) error
	GetAdminData(ctx context.Context, data domain.PageInfo) ([]Admin, int64, error)

	FindByEmailOrLoginName(ctx context.Context, account string) (Admin, error)
	GetAdminByID(ctx context.Context, adminId int64) (Admin, error)
	UpdatePassword(ctx context.Context, adminId int64, password string) error
}

var (
	ErrAdminDuplicate = errors.New("手机号获取邮箱已存在")
	ErrAdminNotFound  = gorm.ErrRecordNotFound
)

type adminDao struct {
	db *gorm.DB
	//p  DBProvider
}

// type DBProvider func() *gorm.DB
//
//	func NewAdminDao1(p DBProvider) AdminDao {
//		res := &adminDao{
//			p: p,
//		}
//		return res
//	}
func NewAdminDao(db *gorm.DB) AdminDao {
	res := &adminDao{
		db: db,
	}
	return res
}

func (a *adminDao) Insert(ctx context.Context, admin Admin) error {
	now := time.Now().UnixMilli()
	admin.CreateTime = now
	admin.UpdateTime = now
	hash, err := bcrypt.GenerateFromPassword([]byte(admin.Password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	admin.Password = string(hash)
	err = a.db.WithContext(ctx).Omit("login_time").Create(&admin).Error
	if mysqlErr, ok := err.(*mysql.MySQLError); ok {
		if mysqlErr.Number == uniqueConflictsErrorNo {
			return ErrAdminDuplicate
		}
	}
	return err
}

func (a *adminDao) Update(ctx context.Context, AdminId int64, admin Admin) error {
	now := time.Now().UnixMilli()
	admin.UpdateTime = now
	err := a.db.WithContext(ctx).Omit("login_time", "create_time", "password").Where("id = ?", AdminId).Updates(&admin).Error
	if mysqlErr, ok := err.(*mysql.MySQLError); ok {
		if mysqlErr.Number == uniqueConflictsErrorNo {
			return ErrAdminDuplicate
		}
	}
	return err
}

func (a *adminDao) UpdateStatus(ctx context.Context, AdminId int64, Status int32) error {
	var admin Admin
	return a.db.Model(&admin).WithContext(ctx).Where("id = ? ", AdminId).Update("status", Status).Error
}

func (a *adminDao) UpdatePassword(ctx context.Context, adminId int64, password string) error {
	var admin Admin
	hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	newPassword := string(hash)
	return a.db.Model(&admin).WithContext(ctx).Where("id = ? ", adminId).Update("password", newPassword).Error
}

func (a *adminDao) GetAdminData(ctx context.Context, data domain.PageInfo) ([]Admin, int64, error) {
	var admin []Admin
	limit := data.Limit
	offset := data.Limit * (data.Page - 1)
	var status = []int32{1, 2}
	var tatol int64
	db := a.db.Model(&Admin{}).WithContext(ctx).Where("status IN (?)", status)
	//db := global.DB.Model(&Admin{}).WithContext(ctx).Where("status IN (?)", status)
	err := db.Count(&tatol).Error
	if err != nil {
		return admin, 0, err
	}
	err = db.Limit(int(limit)).Offset(int(offset)).Order("id desc").Find(&admin).Error
	return admin, tatol, err
}

func (a *adminDao) FindByEmailOrLoginName(ctx context.Context, account string) (Admin, error) {
	var admin Admin
	err := a.db.WithContext(ctx).Where("email = ? or login_name = ? ", account, account).First(&admin).Error
	return admin, err
}

func (a *adminDao) GetAdminByID(ctx context.Context, adminId int64) (Admin, error) {
	var admin Admin
	err := a.db.WithContext(ctx).Where("id = ? ", adminId).First(&admin).Error
	return admin, err
}

type Admin struct {
	ID            int64 `gorm:"primaryKey,autoIncrement"`
	Status        int32 `gorm:"default:1"`
	Password      string
	Email         string
	Mobile        string
	UserType      string
	LoginName     string
	AdminName     string
	RoleIds       string
	HeadSculpture string
	CreateTime    int64
	UpdateTime    int64
	LoginTime     int64
}
